#include "CatmullSubdivider.h"

//==============================================================================
// Public Interface
//==============================================================================

/**
 *	Completes one subdivision iteration, setting the connectivity and 
 *  subdivision meshes within the ModelFrame based on its coarse mesh
 */
void CatmullSubdivider::subdivide( ModelFrame* frame )
{

	// call the super function first
	Subdivider::subdivide(frame);
	
	// only subdivide if there is a coarse mesh loaded
	if( frame->coarse && frame->coarse->n_vertices() > 0)
	{
		prepare( &frame->coarse, &frame->reconnected, &frame->subdivided );
		createMeshes( );
		checkImportance( frame );
		cleanup( &frame->coarse, &frame->reconnected, &frame->subdivided );
	}
}


/**
 *	This function sets the importance mesh when a face is selected, or sets a sharp
 *  edge.  
 * 
 *  The importance mesh will include the subdivided face following Catmull's
 *  subdivision, but with no weights applied to the vertices.  
 * 
 *  For sharp edges, the selected edge will be part of the coarse mesh, so this 
 *  function sets the subdivided edges as sharp and sets the positions of the vertices 
 *  attached to these edges.
 *
 *  If the vertices are found to have more than one sharp edge, now, they will
 *  be either subdivided using a BSpline mask, or will have no subdivision applied.
 */
void CatmullSubdivider::showConnectivity( const Selection* s )
{
	ModelFrame* frame = s->selectionSource;
	if( frame && s && s->type == FACE )
		calcConnectivity( s );
	else if( s && s->type == EDGE )
	{
		EHandle eh = s->selectedEdge;
		//make sure selected edge is valid in the course mesh
		if( !(frame && frame->coarse && frame->coarse->is_valid_handle( s->selectedEdge )) )
			return;		
		doSharpEdgeSetting( frame, eh );
	}
}


/**
 *	
 */
void CatmullSubdivider::showWeights( const Selection* s)
{
	ModelFrame* frame = s->selectionSource;
	if( s && frame && s->type == VERTEX )
		calcWeights( s );
}

//==============================================================================
// SUBDIVISION - Helper Methods (private)
//==============================================================================

/**
 *	This function loads the "connMesh" with the connectivity mesh based on the internal initialized
 *  "mesh".  The "subMesh" also is loaded with the calculated subdivided mesh, which is the
 *  same as the connMesh except it has subdivision weights applied.
 */
void CatmullSubdivider::createMeshes( )
{
	Point p1;
	FIter fit;
	VIter vit;
	EIter eit;
	VData vd;
	FHIter fhit;
	FData fdata;
	VHandle vertex, vertex2;


	/* Compute face midpoints */
	for( fit = mesh->faces_begin(); fit != mesh->faces_end(); ++fit )
	{
		mesh->calc_face_centroid( fit.handle(), p1 );

		/* add face vertices to the connected mesh and subdivided meshes
		 * and save their handles (to use to create faces later) */
		vertex = connMesh->add_vertex( p1 );
		vertex2 = subMesh->add_vertex( p1 );
		connMesh->set_color( vertex, connectedVertexColor );

		//save point in subdivided vertex so we can use it later in edge selection
		vd = subMesh->data( vertex2 );
		vd.setPoint( subMesh->point( vertex2 ) );
		subMesh->data( vertex2 ) = vd;

		//save type of vertex in the connected mesh, used later in weight selection
		vd = connMesh->data( vertex );
		vd.setType( FACE_VERTEX );
		vd.set_importance( fit.handle().idx() );
		connMesh->data( vertex ) = vd;

		fdata = mesh->data( fit.handle() );
		fdata.setIndex( vertex.idx() );
		mesh->data( fit.handle() ) = fdata;

		mesh->property( connF_V, fit.handle() ) = vertex;
		mesh->property( subF_V, fit.handle() ) = vertex2;
	}

	/* Compute positions for edge vertices and add to subdivided mesh and connected mesh */
	for( eit= mesh->edges_begin(); eit != mesh->edges_end(); ++eit)
		computeEdgeMidpoints( eit.handle() );

	/* Compute vertex-vertices and add to connected mesh and subdivided mesh */
	for( vit = mesh->vertices_begin(); vit != mesh->vertices_end(); ++vit )
	{
		//add v_v in connected mesh...and color it green
		vertex = connMesh->add_vertex( mesh->point( vit.handle() ) );
		
		//save type of vertex in the connected mesh, used later in weight selection
		vd = connMesh->data( vertex );
		vd.setType( VERTEX_VERTEX );
		vd.set_index( vit.handle().idx() );
		connMesh->data( vertex ) = vd;

		connMesh->set_color( vertex, coarseVertexColor );
		mesh->property( connV_V, vit.handle() ) = vertex;
		
		//make sure coarse mesh v_v is colored, too
		mesh->set_color( vit.handle(), coarseVertexColor );

		//add v_v in subdivided mesh
		vertex = subMesh->add_vertex( mesh->point( vit.handle() ) );
		mesh->property( subV_V, vit.handle() ) = vertex;

		// save the index in the coarse mesh of the subdivided v_v (need for sharp edge stuff)
		vd = mesh->data( vit.handle() );
		vd.set_index( vertex.idx() );
		mesh->data(  vit.handle() ) = vd;

		// calculate weighted v_v in subdivided mesh
		calculateV_V(  vit.handle() );

		// save weighted v_v point...will need it to undo sharp edge
		vd = subMesh->data( vertex );
		vd.setPoint( subMesh->point( vertex ) );
		subMesh->data( vertex ) = vd;
	}

	/* for each face, will create new faces in connected mesh and subdivided mesh
	 * based on v_v -> e_v -> f_v -> e_v */
	FData fd;
	
	for( fit = mesh->faces_begin(); fit != mesh->faces_end(); ++fit )
	{
		fd = mesh->data( fit.handle() );
		std::vector<int> indices;
		
		for( fhit = mesh->fh_iter(fit.handle()); fhit != false; ++fhit )
			indices.push_back( addFaces( fit, fhit ) );

		// make sure the edges that were sharp in the coarse have been subdivided into
		// sharp edges, too.
		setSharpnessInSubdivided( fit.handle() );

		fd.set_indices( indices );
		mesh->data( fit.handle() ) = fd;
	}
}



/*
 *	
 */
Point CatmullSubdivider::doSubdivisionMask ( PolyMesh*m, PolyMesh*s, VHandle& vh )
{
	HHandle heh1, heh2;
	VEIter veIt;
	VFIter vfIt;
	VHandle vh2;
	Point pNew;
	Point eSum(0,0,0), fSum(0,0,0);
	int n( mesh->valence( vh ) );

	VData vd = m->data( vh );

	/* find the sum of adjacent edge vertices */
	for( veIt = m->ve_iter( vh ); veIt != false; ++veIt )
	{
		EData ed = m->data( veIt.handle() );
		vh2 = s->vertex_handle( ed.importance() );
		eSum += s->point( vh2 );
	}

	/* find the sum of adjacent face points */
	for( vfIt = m->vf_iter( vh ); vfIt != false; ++vfIt )
	{
		m->calc_face_centroid( vfIt.handle(), pNew );
		fSum += pNew;
	}

	/* weighted formula for vertex_vertex point */
	pNew = (PolyMesh::Scalar)((n-2.0)/n) * m->point( vh )  
			+ (PolyMesh::Scalar)(1.0/(n*n))*eSum + (PolyMesh::Scalar)(1.0/(n*n))*fSum;

	return pNew;
}



/*
 *	This function computes the edgepoint for the connected and subdivided mesh for
 *  the specified edge handle.
 *  For connectivity mesh -> the edgepoint is just the midpoint of adjoining vertices
 *  For the subdivided mesh -> the edgepoint is equal to:
 *
 *  1/4 * ( v_adjoinging1 + v_adjoinging2 + face_centroid_left + face_centroid_right )
 *
 *  If the edge specified is a boundary edge, then the subdivided edge point is
 *  calculated using the cubic bspline odd mask (midpoint of edge vertices).
 */
void CatmullSubdivider::computeEdgeMidpoints( EHandle& ehandle )
{
	HHandle heh( mesh->halfedge_handle( ehandle, 0) );
	HHandle opp_heh( mesh->halfedge_handle( ehandle, 1) );
	VHandle fvh1, fvh2, vh1, vh2;
	VData vd;

	/* calculate midpoint of edge - for connected mesh */
	Point  pos1(mesh->point(mesh->to_vertex_handle(heh)));
	Point  pos2(mesh->point(mesh->to_vertex_handle(opp_heh)));
	Point  midpoint( (pos1 + pos2) * 0.5 );
	Point  pNew;

	EData ed = mesh->data( ehandle );

	//check if it's a boundary point or within a sharp edge, if so, apply odd-bspline mask
	if( mesh->is_boundary( ehandle ) || ed.sharpness() )
		pNew = midpoint;
	else
	{
		/* vertex handles for vertices adjoining this edge */
		vh1 = mesh->to_vertex_handle( heh );
		vh2 = mesh->to_vertex_handle( opp_heh );

		/* face handles for faces adjacent to this edge */
		fvh1 = mesh->property( subF_V, mesh->face_handle( opp_heh ) );
		fvh2 = mesh->property( subF_V, mesh->face_handle( heh ) );

		/* calculate the weighted edge point */
		PolyMesh::Scalar s = 0.25;
		pNew = s * ( mesh->point(vh1) + mesh->point(vh2) + subMesh->point(fvh1) + subMesh->point(fvh2) );
	}

	//add the midpoint as the connected mesh edgepoint
	VHandle vertex = connMesh->add_vertex( midpoint );
	connMesh->set_color( vertex, connectedVertexColor );

	//save type of vertex in the connected mesh, used later in weight selection
	vd = connMesh->data( vertex );
	vd.setType( EDGE_VERTEX );
	vd.set_importance( ehandle.idx() );
	connMesh->data( vertex ) = vd;

	/* add midpoint to connected mesh and save handle */
	mesh->property( connE_V, ehandle ) = vertex;

	/* add weighted edge point to subdivided mesh and save handle and its sharpness */
	VHandle vh = subMesh->add_vertex( pNew );
	
	// save this weighted point (need it later for sharp undoing 
	vd = subMesh->data( vh );
	vd.setPoint( pNew );
	subMesh->data( vh ) = vd;

	//and save the index of this edge vertex in the coarse edge (for retrieval later->sharp edge)
	ed.set_importance( vh.idx() );
	mesh->data( ehandle ) = ed;
	mesh->property( subE_V, ehandle ) = vh;
}


/*
 *	This method takes in a handle to a coarse mesh face and creates four new faces
 *  based on this face in the connected mesh and subdivided mesh
 *
 *  These faces are based on the previously calculated vertex-vertices, face-vertices
 *  and edge-vertices.
 *
 *  Each face is created by joining:  vertex_vertex -> edge_vertex -> face_vertex -> edge_vertex
 */
int CatmullSubdivider::addFaces( FIter& fit, FHIter& fhit )
{
	VHandle v_vhandleC, v_vhandleS,
						   e_vhandle1C, e_vhandle1S,
						   e_vhandle2C, e_vhandle2S,
						   f_vhandleC, f_vhandleS;

	/* vertex_vertex */
	v_vhandleC =  mesh->property( connV_V,  mesh->from_vertex_handle( fhit ) );
	v_vhandleS =  mesh->property( subV_V,  mesh->from_vertex_handle( fhit ) );

	/* edge_vertex 1 */
	e_vhandle1C =  mesh->property( connE_V, mesh->edge_handle( fhit.handle() ) );
	e_vhandle1S =  mesh->property( subE_V, mesh->edge_handle( fhit.handle() ) );

	/* face vertex */
	f_vhandleC = mesh->property( connF_V, fit.handle() );
	f_vhandleS = mesh->property( subF_V, fit.handle() );

	/* edge_vertex 2 */
	e_vhandle2C = mesh->property( connE_V, mesh->edge_handle( mesh->prev_halfedge_handle(fhit.handle()) ) );
	e_vhandle2S = mesh->property( subE_V, mesh->edge_handle( mesh->prev_halfedge_handle(fhit.handle()) ) );

	/* add new faces - this OpenMesh internal function creates the edges/halfedges for us */
	FHandle fh = connMesh->add_face( v_vhandleC, e_vhandle1C, f_vhandleC, e_vhandle2C );
	subMesh->add_face( v_vhandleS, e_vhandle1S, f_vhandleS, e_vhandle2S );

	FEIter feIt( connMesh->fe_iter(fh) );
	EData ed;
	for(; feIt != false; ++feIt )
	{
		ed = connMesh->data( feIt.handle() );
		ed.setColor( this->connectedVertexColor );
		connMesh->data( feIt.handle() ) = ed;
	}
	return fh.idx();
}



/**
 *	This function calculates a vertex-vertex in a subdivided mesh given a vertex
 *  handle from the coarse mesh.
 *
 *  The calculation:  v_v = (n-2)/(n*n) * v + (1/(n*n))*SUM(adjoining_edge_points) 
 *							+ (1/(n*n))*SUM(adjoining_face_points)
 *  v = coarse vertex
 *  n = valence of coarse vertex
 *  adjoining_edge_points = are calculated edge points
 *  adjoining_face_points = are calculated face centroids
 * 
 *  If the vertex is a boundary vertex, the cubic bpline even mask is applied
 *  to create the new point:
 *
 *  The calculation:  v_v = (1/8)*v_adjacent_boundary1 + (3/4)*v_coarse + (1/8)*v_adjacent_boundary2
 */
void CatmullSubdivider::calculateV_V( VHandle& vh )
{
	HHandle heh1, heh2;
	VHandle subvh, vh1, vh2;
	VVIter vvIt;
	VFIter vfIt;
	Point pNew;
	Point eSum(0,0,0), fSum(0,0,0);
	int n( mesh->valence( vh ) );

	//check if vertex is sharp (has 2 or more sharp edges attached)
	Sharpness vSharp = isSharp( mesh, vh );

	if( !mesh->is_boundary( vh ) && vSharp==NO_SHARPNESS )
	{
		pNew = doSubdivisionMask ( mesh, subMesh, vh );
	}
	else if( vSharp == ONE_EDGE_BOUNDARY )
		pNew = doVertexBoundary( mesh, vh, true );

	else if( mesh->is_boundary( vh ) || vSharp == CREASE )/* vertex is a boundary or a crease-vertex */
		pNew = doVertexBoundary( mesh, vh );

	else //is a corner point, so do nothing to it
		pNew = mesh->point( vh );
		
	if( vSharp != NO_SHARPNESS )
		connMesh->set_color( mesh->property( connV_V, vh ), sharpEdgeColor );

	/* set the point in the subdivided mesh to be this new calculated point */
	subMesh->set_point(  mesh->property( subV_V, vh ), pNew );
}


//--------------------------------------------------------------------------------------------------
//  IMPORTANCE MESH - HELPER FUNCTIONS
//--------------------------------------------------------------------------------------------------

/**
 *  This function checks the importance mesh after the subdivision algorithm has run.
 *  If there was a previous importance mesh, it is recalculated to reflect the new
 *  reconnected/coarse mesh vertex positions.
 */
void CatmullSubdivider::checkImportance( ModelFrame* frame )
{
	if( frame->getImportanceMesh() )
	{
		int index = 0;
		FHandle fh;
		FData fd;

		
		//create new importance mesh
		PolyMesh* im = new PolyMesh();
		PolyMesh* imOld = frame->getImportanceMesh();

		//go through each face in the old importance mesh and update its vertex
		//positions - which will be the new importance mesh
		FIter fit(imOld->faces_begin()), fend(imOld->faces_end());
		for( ; fit != fend; ++fit )
		{
			fd = imOld->data( fit.handle() );
			fh = frame->coarse->face_handle( fd.importance() );
			loadImportance( frame, fh, im );
		}
		//get the normals for the new importance mesh
		im->request_face_normals();
		im->request_vertex_normals();
		im->update_normals();

		//set the new importance mesh in the frame
		frame->setImportanceMesh(im);
	}
}


/**
 *	This function calculates the importance mesh based on a selected face.
 *  Basically, the importance mesh is the portion of the reconnected mesh that
 *  lies within the selected face.
 */
void CatmullSubdivider::calcConnectivity( const Selection* s )
{
	int index = 0;
	EData ed;
	FHandle fh( s->selectedFace );
	ModelFrame* frame = s->selectionSource;
	PolyMesh* im = new PolyMesh();

	//make sure there is a subdivided frame and make sure the selected face is in the coarse mesh
	if(!( frame->coarse && frame->reconnected && frame->subdivided ))
		return;
	if( !frame->coarse->is_valid_handle( fh ) )
		return;

	if( frame->getImportanceMesh() )
		delete frame->getImportanceMesh();	

	//load the importance mesh with values
	loadImportance( frame, fh, im );

	im->request_face_normals();
	im->request_vertex_normals();
	im->update_normals();
	frame->setImportanceMesh(im);
}


/**
 *	This loads the given "im" mesh with the importance mesh for the specified face handle and
 *  frame.
 */
void CatmullSubdivider::loadImportance( ModelFrame* frame, FHandle fh, PolyMesh* im )
{
	FData fd;
	VData vd;
	FHandle fC;
	FData fdC;
	std::vector< VHandle > vhandles;
	std::vector< int > indices;

	int count = 0;
	fdC = frame->coarse->data( fh );
	indices = fdC.get_indices();
	for( int i(0); i < indices.size(); i++ )
	{
		fC = frame->reconnected->face_handle( indices[i] );

		//set the importance of face vertices and add vertices to
		vhandles.clear();
		PolyMesh::FaceVertexIter fvit( *(frame->reconnected), fC );
		for( ; fvit != false; ++fvit )
		{
			Vec4f color = frame->reconnected->color( fvit.handle() );
			VHandle vertexh = im->add_vertex( frame->reconnected->point( fvit.handle()) );
			vhandles.push_back( vertexh );

			vd = im->data( vertexh );
			vd.set_importance( fvit.handle().idx() );
			double w = frame->reconnected->data( fvit.handle() ).weight();
			vd.set_weight( w );
			im->data( vertexh ) = vd;
			im->set_color(vertexh, color );
		}
		//add face to important mesh
		FHandle face = im->add_face( vhandles );
		//save edge color
		FEIter feit( frame->reconnected->fe_iter( fC ) );
		FEIter feit2( im->fe_iter( face ) );
		for(; feit != false; ++feit )
		{
			EData ed = frame->reconnected->data( feit.handle() );
			im->data( feit2.handle() ) = ed;
			++feit2;
		}

		fd = im->data( face );
		fd.set_importance( fC.idx() );
		im->data( face ) = fd;
	}
}



//--------------------------------------------------------------------------------------------------
//  SHARP EDGES - HELPER FUNCTIONS
//--------------------------------------------------------------------------------------------------

/**
 *	This function calculates the position of a vertex by checking if it's
 *  surrounding edges are sharp.  If it has two sharp edges attached, it's position
 *  will become the coarse vertex with the even bspline mask applied.
 *  If it has three or more sharp edges attached, it will be set to the corresponding 
 *  coarse position.
 */
void CatmullSubdivider::doSharpVertex( ModelFrame* f, VHandle& vh )
{
	Point p;
	VData vd;
	int index = 0;
	Sharpness vSharp = isSharp( f->coarse, vh );
	vd = f->coarse->data( vh );

	if( vSharp == CREASE  )
	{
		//If this vertex has two sharp edges attached to it, apply the even
		//BSpline mask to it, or if it is on a boundary
		p = doVertexBoundary( f->coarse, vh );
		f->subdivided->set_point( f->subdivided->vertex_handle(vd.get_index()), p );
		f->reconnected->set_color( f->reconnected->vertex_handle(vd.get_index()), sharpEdgeColor );
	}
	else if( vSharp == ONE_EDGE_BOUNDARY )
	{
		//If this vertex has two sharp edges attached to it, apply the even
		//BSpline mask to it.
		p = doVertexBoundary( f->coarse, vh, true );
		f->subdivided->set_point( f->subdivided->vertex_handle(vd.get_index()), p );
		f->reconnected->set_color( f->reconnected->vertex_handle(vd.get_index()), sharpEdgeColor );
	}
	else if( vSharp == CORNER )
	{
		//If there are more than two sharp edges attached to this vertex, make sure no
		//subdivision is applied to it (set it as coarse vertex)
		p = f->coarse->point( vh );
		f->subdivided->set_point( f->subdivided->vertex_handle(vd.get_index()), p );
		f->reconnected->set_color( f->reconnected->vertex_handle(vd.get_index()), sharpEdgeColor );
	}
	else if( vSharp == ONE_EDGE )
	{
		//If this vertex has two sharp edges attached to it, apply the even mask to it
		p = doSubdivisionMask( f->coarse, f->subdivided, vh );
		f->subdivided->set_point( f->subdivided->vertex_handle(vd.get_index()), p );
		f->reconnected->set_color( f->reconnected->vertex_handle(vd.get_index()), sharpEdgeColor );
	}
	else
		f->reconnected->set_color( f->reconnected->vertex_handle(vd.get_index()), coarseVertexColor );
}


/**
 *	This function sets the subdivided edges corresponding to the supplied coarse edge
 *  as sharp or not.  The new positions of its corresponding vertices are calculated
 *  and applied, as well.
 */
void CatmullSubdivider::doSharpEdgeSetting( ModelFrame* f, EHandle& eh )
{
	EData ed, le, re;
	VHandle vh1, vh2, vhSub1, vhSub2;
	VData vd1, vd2, vdEdge;
	HHandle heh;
	bool sharpVal;

	ed = f->coarse->data( eh );
	sharpVal = ed.sharpness() ? false : true; 
	ed.set_sharp( sharpVal );
	f->coarse->data( eh ) = ed;

	heh = f->coarse->halfedge_handle(eh,0);
	vh1 = f->coarse->from_vertex_handle(heh);
	vh2 = f->coarse->to_vertex_handle(heh);
	
	// get the edge vertex data corresponding to this edge
	vdEdge = f->subdivided->data( f->subdivided->vertex_handle(ed.importance()) );

	if( sharpVal )
	{
		//find midpoint of two edge vertices...save this as the position of corresponding
		//edge vertex in the subdivided mesh
		Point  pos1(f->coarse->point(vh1));
		Point  pos2(f->coarse->point(vh2));
		Point  midpoint( (pos1 + pos2) * 0.5 );
		f->subdivided->set_point(  f->subdivided->vertex_handle(ed.importance()), midpoint );
		f->reconnected->set_color( f->reconnected->vertex_handle(ed.importance()), sharpEdgeColor );
	}
	else
	{
		f->subdivided->set_point( f->subdivided->vertex_handle(ed.importance()), vdEdge.getPoint() );
		f->reconnected->set_color( f->reconnected->vertex_handle(ed.importance()), connectedVertexColor );
	}
	// now set the edges in the subdivided mesh corresponding to this coarse mesh
	// sharp, as well.
	
	EHandle ledge = f->subdivided->edge_handle(vdEdge.left_edge_index());
	EHandle redge = f->subdivided->edge_handle(vdEdge.right_edge_index());

	// save the sharpness in each subdivided edge
	le = f->subdivided->data( ledge );
	le.set_sharp(sharpVal);
	re = f->subdivided->data( redge );
	re.set_sharp(sharpVal);
	f->subdivided->data( ledge ) = le;
	f->subdivided->data( redge ) = re;

	EData led = connMesh->data( connMesh->edge_handle(ledge.idx()) );
	EData red = connMesh->data( connMesh->edge_handle(redge.idx()) );
		
	// if undoing sharp feature, reset vertex-vertices to old points (and reset color)
	if( !sharpVal )
	{
		led.setColor( coarseVertexColor );
		red.setColor( coarseVertexColor );
		vd1 = f->coarse->data( vh1 );
		vd2 = f->coarse->data( vh2 );
		vhSub1 = f->subdivided->vertex_handle(vd1.get_index());
		vhSub2 = f->subdivided->vertex_handle(vd2.get_index());

		f->subdivided->set_point( vhSub1, f->subdivided->data(vhSub1).getPoint() );
		f->subdivided->set_point( vhSub2,  f->subdivided->data(vhSub2).getPoint() );
	}
	else
	{
		led.setColor( sharpEdgeColor );
		red.setColor( sharpEdgeColor );
	}
	connMesh->data( connMesh->edge_handle(ledge.idx()) ) = led;
	connMesh->data( connMesh->edge_handle(redge.idx()) ) = red;

	//recalculate surrounding subdivided points with sharp edge added/remove
	doSharpVertex( f, vh1 );
	doSharpVertex( f, vh2 );
}



void CatmullSubdivider::calcWeights( const Selection* s )
{
	int index = 0;
	EData ed;
	VHandle vh( s->selectedVertex );
	ModelFrame* frame = s->selectionSource;
	PolyMesh* im = new PolyMesh();

	//make sure there is a subdivided frame and make sure the selected face is in the coarse mesh
	if(!( frame->coarse && frame->reconnected && frame->subdivided ))
		return;
	if( !frame->reconnected->is_valid_handle( vh ) )
		return;

	if( frame->getImportanceMesh() )
	{
		frame->deleteImportance();
	}

	this->clearWeights( frame->reconnected );
	//load the importance mesh with values
	loadImportance( frame, vh, im );

	im->request_face_normals();
	im->request_vertex_normals();
	im->update_normals();
	frame->setImportanceMesh(im);
}


/**
 *	This loads the given "im" mesh with the importance mesh for the specified vertex handle and
 *  frame.
 */
void CatmullSubdivider::loadImportance( ModelFrame* frame, VHandle& vh, PolyMesh* im )
{
	FData fd;
	VData vd, vdSub;
	FHandle fC;
	FData fdC;

	PolyMesh::EdgeIter eIt;
	PolyMesh::EdgeIter eIt2;

	vd = frame->reconnected->data( vh );
	vd.setColor( frame->reconnected->color( vh ) );
	frame->reconnected->set_color( vh, Vec4f(  0.75, 0, 0.2, 1 ));

	if( vd.getType() == EDGE_VERTEX )
	{
		// get the edges on the left and right of this vertex and the original edge
		// from coarse mesh
		EHandle left, right, coarse;
		coarse = frame->coarse->edge_handle( vd.importance() );
		
		// now get the vertices in coarse mesh
		HHandle heh;
		VHandle vh1, vh2;
		heh = frame->coarse->halfedge_handle( coarse, 0 );
		vh1 = frame->coarse->from_vertex_handle( heh );
		vh2 = frame->coarse->to_vertex_handle( heh );

		// which will help us get the vertices in the connected mesh
		vh1 = frame->reconnected->vertex_handle( frame->coarse->data( vh1 ).get_index() );
		vh2 = frame->reconnected->vertex_handle( frame->coarse->data( vh2 ).get_index() );

		//now get the faces adjacent to this edge vertex in the coarse mesh
		FHandle fhLeft, fhRight;
		fhLeft = frame->coarse->face_handle( heh );
		fhRight = frame->coarse->face_handle( frame->coarse->opposite_halfedge_handle( heh ) );

		//and the face vertices
		VHandle fv1, fv2;
		int index1 = frame->coarse->data( fhLeft ).getIndex();
		int index2 =  frame->coarse->data( fhRight ).getIndex();
		fv1 = frame->reconnected->vertex_handle( index1 );
		fv2 = frame->reconnected->vertex_handle( index2 );

		//now save the weights in the face vertices and vertex vertices
		VData vad, vbd, fvd1, fvd2;
		vad = frame->reconnected->data( vh1 );
		vbd = frame->reconnected->data( vh2 );
		fvd1 = frame->reconnected->data( fv1 );
		fvd2 = frame->reconnected->data( fv2 );
		vad.set_weight( 1.0/4.0 );
		vbd.set_weight( 1.0/4.0 );
		fvd1.set_weight( 1.0/4.0 );
		fvd2.set_weight( 1.0/4.0 );
		frame->reconnected->data( vh1 ) = vad;
		frame->reconnected->data( vh2 ) = vbd;
		frame->reconnected->data( fv1 ) = fvd1;
		frame->reconnected->data( fv2 ) = fvd2;

		//and create importance mesh
		this->loadImportance( frame, fhRight, im );
		this->loadImportance( frame, fhLeft, im );
	}
	else if( vd.getType() == FACE_VERTEX )
	{
		// get coarse mesh face
		FHandle fh;
		FVIter fvit;
		VHandle vh;
		VData vdata;
		fh = frame->coarse->face_handle( vd.importance() );
		fvit = frame->coarse->fv_iter( fh );
		int valence = frame->coarse->valence( fh );
		
		//set weights in reconnected mesh corresponding to this face
		for( ; fvit != false; ++fvit )
		{
			vh = frame->reconnected->vertex_handle( frame->coarse->data( fvit.handle() ).get_index() );
			vdata = frame->reconnected->data( vh );
			vdata.set_weight( 1.0/(double)valence );
			frame->reconnected->data( vh ) = vdata;
		}
		//now add the face to important mesh
		this->loadImportance( frame, fh, im );
	}
	else
	{
		VData vdata;
		FData fdata;
		//get the coarse vertex
		VHandle vcoarse = frame->coarse->vertex_handle( vd.get_index() );

		//get valence of vertex and set weight values
		int n = frame->coarse->valence( vcoarse );
		double v_weight = ((double)n - 2.0)/(double)n;
		double weight = (1.0/((double)n * (double)n));

		//now set the weight for the vi
		vd.set_weight( v_weight );
		frame->reconnected->data( vh ) = vd;

		//set the edge vertices weights
		VVIter vvit( frame->reconnected->vv_iter( vh ) );
		for( ; vvit != false; ++vvit )
		{
			vdata = frame->reconnected->data( vvit.handle() );
			vdata.set_weight( weight );
			frame->reconnected->data( vvit.handle() ) = vdata;
		}

		//set the weights for the face vertices surrounding the selected vertex
		VFIter vfit( frame->coarse->vf_iter( vcoarse ) );
		for( ; vfit != false; ++vfit )
		{
			fdata = frame->coarse->data( vfit.handle() );
			vdata = frame->reconnected->data( frame->reconnected->vertex_handle( fdata.getIndex() ));
			vdata.set_weight( weight );
			frame->reconnected->data( frame->reconnected->vertex_handle( fdata.getIndex() ) ) = vdata;
		}
		//add the faces to the important mesh
		vfit = frame->coarse->vf_iter( vcoarse );
		for( ; vfit != false; ++vfit )
			this->loadImportance( frame, vfit.handle(), im );
	}
}
